package com.huashizhaoxi.lionapp.controller;

import com.google.gson.Gson;
import com.huashizhaoxi.lionapp.config.WxPayConfig;
import com.huashizhaoxi.lionapp.entity.Payment;
import com.huashizhaoxi.lionapp.entity.Result;
import com.huashizhaoxi.lionapp.service.PayService;
import com.huashizhaoxi.lionapp.utils.HttpUtils;
import com.huashizhaoxi.lionapp.utils.WechatPay2ValidatorForRequest;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.logging.Logger;

@RestController
@RequestMapping("/pay")
public class PayController {

    @Resource
    private WxPayConfig wxPayConfig;

    @Resource
    private CloseableHttpClient wxPayClient;

    @Resource
    private Verifier verifier;

    @Autowired
    private PayService payService;


    Logger log = Logger.getLogger(PayController.class.getName());

    /**
     * 微信通知回调地址
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/notify")
    public String notify(HttpServletRequest request, HttpServletResponse response){

        Gson gson = new Gson();
        //创建一个应答对象

        HashMap<String, String> map = new HashMap<>();

        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            HashMap<String,Object> bodyMap = gson.fromJson(body, HashMap.class);

            String requestId = (String) bodyMap.get("id");

            log.info("支付通知的id=====》》》"+bodyMap.get("id"));
//            log.info("支付通知的完整数据=====》》》{}",body);

            //TODO : 签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier, requestId,body);
            if (!wechatPay2ValidatorForRequest.validate(request)) {
                log.warning("通知验签失败");
                //通知失败应答
                response.setStatus(500);
                map.put("code","ERROR");
                map.put("message","通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");
            //TODO : 处理订单


            //解密密文，获取明文
            String plaintText = wxPayConfig.decryptFromResource(bodyMap);
            //将明文转为map
            HashMap plaintTextMap = gson.fromJson(plaintText, HashMap.class);


            //获取支付下单的时候，传入的商户订单号,可以根据这个订单号去获取我们的一个订单记录，从而更新订单状态
            String orderNo = (String) plaintTextMap.get("out_trade_no");
            //业务编号
            String transactionId = (String) plaintTextMap.get("transaction_id");
            //trade_type，支付类型,如果有需要的话， 你可以存储在数据库中，这里我们的数据，基本上都是JSapi支付类型
            String tradeType = (String) plaintTextMap.get("trade_type");
            //交易状态
            String tradeState = (String) plaintTextMap.get("trade_state");


            /**
             * 在更新你订单状态之前，可以先根据orderNo，查询数据库中是否有这个订单
             * 然后查询这个订单是否已经被处理过，也就是状态是否是已经支付的状态
             * 如果这个订单已经被处理了，那么我们可以直接return，没有被处理过我们在处理
             * 这样可以避免数据库被反复的操作
             *
             * 微信官方的解释是：
             *  同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
             *  推荐的做法是，当商户系统收到通知进行处理时，先检查对应业务数据的状态，
             *  并判断该通知是否已经处理。如果未处理，则再进行处理；如果已处理，
             *  则直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，
             *  以避免函数重入造成的数据混乱。
             */
            int orderStatus = payService.checkOrder(orderNo);
            if (orderStatus == 2&&tradeState.equals("SUCCESS")){
                //已经处理过了，直接返回成功
                response.setStatus(200);
                map.put("code","SUCCESS");
                map.put("message","成功");
                return gson.toJson(map);
            }
            if(!tradeState.equals("SUCCESS")){
                //支付失败
                response.setStatus(500);
                map.put("code","ERROR");
                map.put("message","支付失败");
                return gson.toJson(map);
            }

            //更新订单状态
            /*
             * 你的数据库操作
             * 一定要存储解密出来的transaction_id字段在数据库中
             * 如果需要跟微信官方对账的话，是需要提供这个字段进行一个查账的
             * */
            //TODO : 更新订单状态
            payService.updateOrder(orderNo,transactionId);
            //成功应答
            response.setStatus(200);
            map.put("code","SUCCESS");
            map.put("message","成功");
            return gson.toJson(map);
        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code","ERROR");
            map.put("message","失败");
            return gson.toJson(map);
        }
    }

    /**
     * 提供给前端查询支付订单状态的接口
     * @param orderNo
     * @return
     */
    @GetMapping("/query-order-status/{orderNo}")
    public Result queryOderStatus(@PathVariable("orderNo") String orderNo){
        try{
            int orderStatus = payService.checkOrder(orderNo);
            return Result.success("查询成功",orderStatus);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("查询失败");
        }
    }

    @GetMapping("/cancel-order/{orderNo}/{type}")
    public Result cancelOrder(@PathVariable("orderNo") String orderNo){
        try{
            payService.changeState(orderNo,0);
            return Result.success("取消成功",null);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("取消失败");
        }
    }

    @GetMapping("/change-state/{orderNo}/{state}")
    public Result changeState(@PathVariable("orderNo") String orderNo,@PathVariable("state") int state){
        try{
            payService.changeState(orderNo,state);
            return Result.success("修改成功",null);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("修改失败");
        }
    }

    @GetMapping("/get-pay-config/{orderNo}")
    public Result getPayConfig(@PathVariable("orderNo") String orderNo){
        try{
            Payment payConfig = payService.getPayConfig(orderNo);
            return Result.success("获取成功",payConfig);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("获取失败");
        }
    }



}
